#-*- encoding: utf-8 -*-
import traceback
import os,sys, time, platform
from optparse import OptionParser

def do_pause(code=0):
	if platform.system() == 'Windows':
		os.system("pause")
	   
def do_exit(code=1):
	do_pause()
	sys.exit(code)

def _print(strval):
	#if platform.system() == 'Windows':
	#	strval = strval.encode('GBK')
	print(strval)
	
def parseOption(args):
    optparser = OptionParser(usage="%prog [optinos]")
    optparser.add_option('--proto_path', action='store', dest='proto_path', help='proto file path')
    optparser.add_option('--cpp_out', action='store', dest='cpp_out', help='output cpp dir(default current dir)')
    (opt, args) = optparser.parse_args(args)
    if not opt.proto_path or not opt.cpp_out:
        optparser.print_help()
        do_exit(1)
    return (opt, args)

def base_type() :
	return {'bool':'bool', 'int32':'int32_t', 'int64':'int64_t', 'uint32':'uint32_t', 'uint64':'uint64_t', 'float':'float', 'double':'double', 'string':'std::string', 'bytes':'std::string'}
def get_base_type(type) :
	base_type_map = base_type()
	if type in base_type_map :
		return base_type_map[type]
	return type
def is_base_type(type) :
	if type in base_type() :
		return True
	return False

def get_cpp_field_type(field) :
	cpp_base_type = get_base_type(field['type'])
	cpp_field_type = cpp_base_type
	if field['array'] == True:
		if field['is_proto_msg'] == True :
			cpp_field_type = "::miniproto::RepeatedField<%s>*" % (cpp_base_type)
		elif field['type'] == "string" or field['type'] == "bytes":
			cpp_field_type = "::miniproto::Message::StringList"
		else :
			cpp_field_type = "std::vector< %s >" % (cpp_base_type)
	else :
		if field['is_proto_msg'] == True :
			cpp_field_type = cpp_base_type + "*"
	return (cpp_base_type, cpp_field_type)

def get_field_descriptor_type(type, is_array) :
	descriptor_type = ''
	if type == 'bool' :
		descriptor_type = "::miniproto::ProtoFieldDescriptor::BOOL"
	elif type == "int32" :
		descriptor_type = "::miniproto::ProtoFieldDescriptor::INT32"
	elif type == "int64" :
		descriptor_type = "::miniproto::ProtoFieldDescriptor::INT64"
	elif type == "uint32" :
		descriptor_type = "::miniproto::ProtoFieldDescriptor::UINT32"
	elif type == "uint64" :
		descriptor_type = "::miniproto::ProtoFieldDescriptor::UINT64"
	elif type == "float" :
		descriptor_type = "::miniproto::ProtoFieldDescriptor::FLOAT"
	elif type == "double" :
		descriptor_type = "::miniproto::ProtoFieldDescriptor::DOUBLE"
	elif type == "string" :
		descriptor_type = "::miniproto::ProtoFieldDescriptor::STRING"
	elif type == "bytes" :
		descriptor_type = "::miniproto::ProtoFieldDescriptor::BYTES"
	else :
		descriptor_type = "::miniproto::ProtoFieldDescriptor::MESSAGE"
	if is_array == True :
		descriptor_type = "(%s | ::miniproto::ProtoFieldDescriptor::ARRAY)" % (descriptor_type)
	return descriptor_type

def convert_field_name(field_name) :
	if field_name == "auto" :
		return field_name + "_"
	return field_name

#############################################################
def read_proto_file(proto_filepath, message_name_list) :
	message_map = {}
	include_list = []
	with open(proto_filepath, 'r', encoding='utf-8') as protofile :
		flag_message_start = 0
		message_name = ""
		message_field_list = []
		for line in protofile:
			line = line.strip()
			if line.find("import") >= 0 :
				import_file = line.split('"')[1]
				include_list.append(import_file)
				continue
			if line[0:8] == "message ":
				message_name = line.split(" ")[1]
				message_field_list = []
				flag_message_start = 1
				message_name_list.append(message_name)
				_print("gen message: %s" % (message_name))
				continue
			if line[0:1] == "}" :
				message_map[message_name] = message_field_list
				message_name = ""
				message_field_list = []
				flag_message_start = 0
				continue
			if (line.find("optional") >= 0 or line.find("required") >= 0) and flag_message_start == 1 :
				field = {}
				line_words = line.split(";")[0].split(" ")
				field['array'] = False
				field['type'] = line_words[1]
				field['name'] = convert_field_name(line_words[2])
				field['number'] = line_words[4]
				field['is_proto_msg'] = (is_base_type(field['type']) == False)
				#_print(field)
				message_field_list.append(field)
				continue
			if line.find("repeated") >= 0 and flag_message_start == 1 :
				field = {}
				line_words = line.split(";")[0].split(" ")
				field['array'] = True
				field['type'] = line_words[1]
				field['name'] = convert_field_name(line_words[2])
				field['number'] = line_words[4]
				field['is_proto_msg'] = (is_base_type(field['type']) == False)
				#_print(field)
				message_field_list.append(field)
	return (message_map, include_list, message_name_list)

def generate_message_h(message_map, include_list, cpp_filepath, filename) :
	head_file_path = os.path.join(cpp_filepath, filename + ".pb.h")
	with open(head_file_path, "w+", encoding='utf-8') as head_file :
		head_file.write("// Auto generate.  DO NOT EDIT!\n")
		head_file.write("// source: %s.proto\n" % (filename))
		head_file.write("#ifndef PROTOBUF_%s_2eproto__INCLUDED\n" % (filename))
		head_file.write("#define PROTOBUF_%s_2eproto__INCLUDED\n" % (filename))
		head_file.write("#include \"Message.h\"\n")
		head_file.write("#include \"MessageDescriptor.h\"\n")
		for include in include_list :
			(include_name,include_ext) = os.path.splitext(include)
			head_file.write("#include \"%s.pb.h\"\n" % (include_name))
		if filename == "ProtoPublic" or filename == "ProtoInnerPublic":
			for message_name in message_map :
				head_file.write("class %s;\n" % (message_name))
		for message_name, field_list in message_map.items() :
			head_file.write("class %sDescriptor : public ::miniproto::MessageDescriptor {\n" % (message_name))
			head_file.write("public:\n")
			head_file.write("    virtual void init();\n")
			head_file.write("    static %sDescriptor *instance(void);\n" % (message_name))
			head_file.write("    static %sDescriptor *instance_;\n" % (message_name))
			head_file.write("}; // %sDescriptor\n" % (message_name))
			head_file.write("class %s : public ::miniproto::Message {\n" % (message_name))
			head_file.write("public:\n")
			head_file.write("    %s(bool reflection = true);\n" % (message_name))
			head_file.write("    ~%s();\n" % (message_name))
			head_file.write("    %s &operator=(const %s &obj);\n" % (message_name, message_name))
			head_file.write("    %s(const %s &obj);\n" % (message_name, message_name))
			head_file.write("    virtual %s* New() const;\n" % (message_name))
			head_file.write("    virtual void Destroy();\n")
			head_file.write("    // filed gen here\n")
			for field in field_list :
				(cpp_base_type, cpp_field_type) = get_cpp_field_type(field)
				field_name = field['name'].lower()
				field_type = field['type']
				#_print("%s, %s, %s, %s, %s" % (message_name, field['array'], field['is_proto_msg'], field_name, field_type))
				head_file.write("    bool has_%s() const;\n" % (field_name))
				head_file.write("    void clear_%s();\n" % (field_name))
				if field['array'] == True:
					if field['is_proto_msg'] == True :
						head_file.write("    int %s_size() const;\n" % (field_name))
						head_file.write("    const ::%s& %s(int index) const;\n" % (cpp_base_type, field_name))
						head_file.write("    const ::miniproto::RepeatedField< %s >& %s() const;\n" % (cpp_base_type, field_name))
						head_file.write("    ::miniproto::RepeatedField< %s >* mutable_%s();\n" % (cpp_base_type, field_name))
						head_file.write("    ::%s* mutable_%s(int index);\n" % (cpp_base_type, field_name))
						head_file.write("    ::%s* add_%s();\n" % (cpp_base_type, field_name))
					elif field_type == "string" or field_type == "bytes" :
						head_file.write("    int %s_size() const;\n" % (field_name))
						head_file.write("    const ::std::string& %s(int index) const;\n" % (field_name))
						head_file.write("    ::std::string* mutable_%s(int index);\n" % (field_name))
						head_file.write("    void set_%s(int index, const ::std::string& value);\n" % (field_name))
						head_file.write("    void set_%s(int index, const char* value, size_t size);\n" % (field_name))
						head_file.write("    ::std::string* add_%s();\n" % (field_name))
						head_file.write("    void add_%s(const ::std::string& value);\n" % (field_name))
						head_file.write("    void add_%s(const char* value, size_t size);\n" % (field_name))
					else:
						head_file.write("    int %s_size() const;\n" % (field_name))
						head_file.write("    %s %s(int index) const;\n" % (cpp_base_type, field_name))
						head_file.write("    void set_%s(int index, %s value);\n" % (field_name, cpp_base_type))
						head_file.write("    void add_%s(%s value);\n" % (field_name, cpp_base_type))
				else:
					if field['is_proto_msg'] == True :
						head_file.write("    const ::%s& %s() const;\n" % (cpp_base_type, field_name))
						head_file.write("    ::%s* mutable_%s();\n" % (cpp_base_type, field_name))
					elif field_type == "string" or field_type == "bytes" :
						head_file.write("    void set_%s(const ::std::string &val);\n" % (field_name))
						head_file.write("    void set_%s(const char* value, size_t size);\n" % (field_name))
						head_file.write("    ::std::string* mutable_%s();\n" % (field_name))
						head_file.write("    const ::std::string &%s() const;\n" % (field_name))
					else:
						head_file.write("    %s %s() const;\n" % (cpp_base_type, field_name))
						head_file.write("    void set_%s(%s val);\n" % (field_name, cpp_base_type))
			head_file.write("private:\n")
			head_file.write("    virtual void init_reflection();\n")
			head_file.write("    // filed gen here\n")
			for field in field_list :
				(cpp_base_type, cpp_field_type) = get_cpp_field_type(field)
				field_name = field['name'].lower()
				head_file.write("    %s %s_;\n" % (cpp_field_type, field_name))
			head_file.write("}; // %s\n" % (message_name))
		head_file.write("#endif	// PROTOBUF_%s_2eproto__INCLUDED\n" % (filename))

def generate_message_cpp(message_map, cpp_filepath, filename) :
	cpp_file_path = os.path.join(cpp_filepath, filename + ".pb.cc")
	with open(cpp_file_path, "w+", encoding='utf-8') as cpp_file :
		cpp_file.write("// Auto generate.  DO NOT EDIT!\n")
		cpp_file.write("#include \"%s.pb.h\"\n" % (filename))
		cpp_file.write("#include \"ProtoFieldDescriptor.h\"\n")
		cpp_file.write("#include \"ProtoField.h\"\n")
		cpp_file.write("#include \"RepeatedField.h\"\n")
		cpp_file.write("#include \"MessageFactoryImp.h\"\n")
		for message_name, field_list in message_map.items() :
			cpp_file.write("void %sDescriptor::init() {\n" % (message_name))
			cpp_file.write("    this->type_name_ = \"%s\";\n" % (message_name))
			cpp_file.write("    this->resize(%d);\n" % (len(field_list)))
			contruct_func_code = []
			deconstruct_func_code = []
			for field in field_list :
				field_name = field['name'].lower()
				field_type = field['type']
				field_number = int(field['number'])
				descriptor_type = get_field_descriptor_type(field_type, field['array'])
				if field['is_proto_msg'] == True :
					cpp_file.write("    this->set_message_field_desc(%s, \"%s\", %d, new %s(false));\n" % (descriptor_type, field_name, field_number, field_type))
				else :
					cpp_file.write("    this->set_field_desc(%s, \"%s\", %d);\n" % (descriptor_type, field_name, field_number))

				## constuct fuction code
				if is_base_type(field_type) == True and field_type != "string" and field_type != "bytes" and field['array'] == False :
					contruct_func_code.append("    this->%s_ = 0;\n" % (field_name))
				elif field['is_proto_msg'] == True :
					if field['array'] == False :
						contruct_func_code.append("    this->%s_ = new %s();\n" % (field_name, field_type))
					else:
						contruct_func_code.append("    this->%s_ = new ::miniproto::RepeatedField<%s>();\n" % (field_name, field_type))
				## deconstruct function code
				if (field_type == "string" or field_type == "bytes") and field['array'] == True :
					deconstruct_func_code.append("    {for (::miniproto::Message::StringList::iterator iter = this->%s_.begin(); iter != this->%s_.end(); ++iter) delete (*iter);\n" % (field_name, field_name))
					deconstruct_func_code.append("    ::miniproto::Message::StringList tmp;this->%s_.swap(tmp);}\n" % (field_name))
				elif field['is_proto_msg'] == True :
					deconstruct_func_code.append(" delete this->%s_;" % (field_name))
			cpp_file.write("}\n")
			cpp_file.write("%sDescriptor *%sDescriptor::instance_ = NULL;\n" % (message_name, message_name))
			cpp_file.write("%sDescriptor *%sDescriptor::instance() {\n" % (message_name, message_name))
			cpp_file.write("    if (%sDescriptor::instance_ == NULL) {\n" % (message_name))
			cpp_file.write("        %sDescriptor::instance_ = new %sDescriptor();\n" % (message_name, message_name))
			cpp_file.write("        %sDescriptor::instance_->init();\n" % (message_name))
			cpp_file.write("    }\n")
			cpp_file.write("    return %sDescriptor::instance_;\n" % (message_name))
			cpp_file.write("}\n")
			cpp_file.write("%s::%s(bool reflection) {\n" % (message_name, message_name))
			cpp_file.writelines(contruct_func_code)
			cpp_file.writelines("    if (reflection) this->init_reflection();\n")
			contruct_func_code.append("    this->init_reflection();\n")
			cpp_file.write("}\n")
			cpp_file.write("%s::~%s(){\n" % (message_name, message_name))
			cpp_file.writelines(deconstruct_func_code)
			cpp_file.write("}\n")
			cpp_file.write("%s& %s::operator=(const %s& obj){ this->CopyFrom(obj);return *this; }\n" % (message_name, message_name, message_name))
			cpp_file.write("%s::%s(const %s& obj) {\n" % (message_name, message_name, message_name))
			cpp_file.writelines(contruct_func_code)
			cpp_file.write("    this->MergeFrom(obj);\n")
			cpp_file.write("}\n")
			cpp_file.write("%s* %s::New() const { return new %s(); }\n" % (message_name, message_name, message_name))
			cpp_file.write("void %s::Destroy() { delete this; }\n" % (message_name))
			init_reflection_code = []
			init_reflection_code.append("    this->field_list_->resize(%d);\n" % (len(field_list)))
			for field in field_list :
				(cpp_base_type, cpp_field_type) = get_cpp_field_type(field)
				field_name = field['name'].lower()
				field_type = field['type']
				field_number = int(field['number'])
				field_set_code = "    this->field_list_->at(%d)->set_field_set(true);\n" % (field_number - 1)
				init_reflection_code.append("    field = new ::miniproto::ProtoField();\n")
				cpp_file.write("bool %s::has_%s() const { return this->field_list_->at(%d)->is_field_set(); }\n" % (message_name, field_name, field_number - 1))
				cpp_file.write("void %s::clear_%s() { this->field_list_->at(%d)->Clear(); }\n" % (message_name, field_name, field_number - 1))
				if field['array'] == True:
					if field['is_proto_msg'] == True :
						cpp_file.write("int %s::%s_size() const { return this->%s_->size(); }\n" % (message_name, field_name, field_name))
						cpp_file.write("const ::%s& %s::%s(int index) const { return this->%s_->at(index); }\n" % (cpp_base_type, message_name, field_name, field_name))
						cpp_file.write("const ::miniproto::RepeatedField< %s >& %s::%s() const {\n" % (cpp_base_type, message_name, field_name))
						cpp_file.write("    return *(this->%s_);\n" % (field_name))
						cpp_file.write("}\n")
						cpp_file.write("::miniproto::RepeatedField< %s >* %s::mutable_%s() {\n" % (cpp_base_type, message_name, field_name))
						cpp_file.write(field_set_code)
						cpp_file.write("    return this->%s_;\n" % (field_name))
						cpp_file.write("}\n")
						cpp_file.write("::%s* %s::mutable_%s(int index) {\n" % (cpp_base_type, message_name, field_name))
						cpp_file.write(field_set_code)
						cpp_file.write("    return &(this->%s_->at(index));\n" % (field_name))
						cpp_file.write("}\n")
						cpp_file.write("::%s* %s::add_%s() {\n" % (cpp_base_type, message_name, field_name))
						cpp_file.write(field_set_code)
						cpp_file.write("    return this->%s_->Add();\n" % (field_name))
						cpp_file.write("}\n")

						init_reflection_code.append("    field->init_field_message_list(&(this->%s_->message_list()));\n" % (field_name))
					elif field_type == "string" or field_type == "bytes" :
						cpp_file.write("int %s::%s_size() const { return this->%s_.size(); }\n" % (message_name, field_name, field_name))
						cpp_file.write("const ::std::string& %s::%s(int index) const { return *(this->%s_.at(index)); }\n" % (message_name, field_name, field_name))
						cpp_file.write("::std::string* %s::mutable_%s(int index) {\n" % (message_name, field_name))
						cpp_file.write(field_set_code)
						cpp_file.write("    return this->%s_.at(index);\n" % (field_name))
						cpp_file.write("}\n")
						cpp_file.write("void %s::set_%s(int index, const ::std::string& value) {\n" % (message_name, field_name))
						cpp_file.write(field_set_code)
						cpp_file.write("    this->%s_[index]->assign(value);\n" % (field_name))
						cpp_file.write("}\n")
						cpp_file.write("void %s::set_%s(int index, const char* value, size_t size) {\n" % (message_name, field_name))
						cpp_file.write(field_set_code)
						cpp_file.write("    this->%s_[index]->assign(value, size);\n" % (field_name))
						cpp_file.write("}\n")
						cpp_file.write("::std::string* %s::add_%s() {\n" % (message_name, field_name))
						cpp_file.write(field_set_code)
						cpp_file.write("    ::std::string* val = new ::std::string();\n")
						cpp_file.write("    this->%s_.push_back(val);\n" % (field_name))
						cpp_file.write("    return val;\n")
						cpp_file.write("}\n")
						cpp_file.write("void %s::add_%s(const ::std::string& value) {\n" % (message_name, field_name))
						cpp_file.write(field_set_code)
						cpp_file.write("    ::std::string* val = new ::std::string(value);\n")
						cpp_file.write("    this->%s_.push_back(val);\n" % (field_name))
						cpp_file.write("}\n")
						cpp_file.write("void %s::add_%s(const char* value, size_t size) {\n" % (message_name, field_name))
						cpp_file.write(field_set_code)
						cpp_file.write("    ::std::string* val = new ::std::string(value, size);\n")
						cpp_file.write("    this->%s_.push_back(val);\n" % (field_name))
						cpp_file.write("}\n")

						init_reflection_code.append("    field->init_field_%s_list(&(this->%s_));\n" % (field_type, field_name))
					else:
						cpp_file.write("int %s::%s_size() const { return this->%s_.size(); }\n" % (message_name, field_name, field_name))
						cpp_file.write("%s %s::%s(int index) const{ return this->%s_.at(index); }\n" % (cpp_base_type, message_name, field_name, field_name))
						cpp_file.write("void %s::set_%s(int index, %s value) {\n" % (message_name, field_name, cpp_base_type))
						cpp_file.write(field_set_code)
						cpp_file.write("    this->%s_[index] = value;\n" % (field_name))
						cpp_file.write("}\n")
						cpp_file.write("void %s::add_%s(%s value) {\n" % (message_name, field_name, cpp_base_type))
						cpp_file.write(field_set_code)
						cpp_file.write("    this->%s_.push_back(value);\n" % (field_name))
						cpp_file.write("}\n")

						init_reflection_code.append("    field->init_field_%s_list(&(this->%s_));\n" % (field_type, field_name))
				else:
					if field['is_proto_msg'] == True :
						cpp_file.write("const ::%s& %s::%s() const{ return *(this->%s_); }\n" % (cpp_base_type, message_name, field_name, field_name))
						cpp_file.write("::%s* %s::mutable_%s(){ this->field_list_->at(%d)->set_field_set(true);return this->%s_; }\n" % (cpp_base_type, message_name, field_name, field_number - 1, field_name))

						init_reflection_code.append("    field->init_field_message(this->%s_);\n" % (field_name))
					elif field_type == "string" or field_type == "bytes" :
						cpp_file.write("void %s::set_%s(const ::std::string &val){ this->field_list_->at(%d)->set_field_set(true);this->%s_.assign(val); }\n" % (message_name, field_name, field_number - 1, field_name))
						cpp_file.write("void %s::set_%s(const char* value, size_t size){ this->field_list_->at(%d)->set_field_set(true);this->%s_.assign(value, size); }\n" % (message_name, field_name, field_number - 1, field_name))
						cpp_file.write("::std::string* %s::mutable_%s(){ this->field_list_->at(%d)->set_field_set(true);return &(this->%s_); }\n" % (message_name, field_name, field_number - 1, field_name))
						cpp_file.write("const ::std::string &%s::%s() const{ return this->%s_; }\n" % (message_name, field_name, field_name))

						init_reflection_code.append("    field->init_field_%s(&(this->%s_));\n" % (field_type, field_name))
					else:
						cpp_file.write("%s %s::%s() const{ return this->%s_; }\n" % (cpp_base_type, message_name, field_name, field_name))
						cpp_file.write("void %s::set_%s(%s val){ this->field_list_->at(%d)->set_field_set(true);this->%s_ = val; }\n" % (message_name, field_name, cpp_base_type, field_number - 1, field_name))

						init_reflection_code.append("    field->init_field_%s(&(this->%s_));\n" % (field_type, field_name))
				init_reflection_code.append("    (*(this->field_list_))[%d] = field;\n" % (field_number - 1))
			cpp_file.write("// auto gen field interface\n")
			cpp_file.write("void %s::init_reflection() {\n" % (message_name))
			cpp_file.write("    this->message_descriptor_ = %sDescriptor::instance();\n" % (message_name))
			cpp_file.write("    this->message_factory_ = MessageFactoryImp::instance();\n")
			cpp_file.write("    ::miniproto::ProtoField *field = NULL;\n")
			cpp_file.writelines(init_reflection_code)
			cpp_file.write("}\n")

def generate_message_factory_imp(head_file_list, message_name_list, cpp_filepath):
	head_file_path = os.path.join(cpp_filepath, "MessageFactoryImp.h")
	with open(head_file_path, "w+", encoding='utf-8') as head_file :
		head_file.write("// Auto generate.  DO NOT EDIT!\n")
		head_file.write("#ifndef _MESSAGEFACTORYIMP_H_\n")
		head_file.write("#define _MESSAGEFACTORYIMP_H_\n")
		head_file.write("#include \"MessageFactory.h\"\n")
		head_file.write("class MessageFactoryImp : public miniproto::MessageFactory\n")
		head_file.write("{\n")
		head_file.write("public:\n")
		head_file.write("    MessageFactoryImp();\n")
		head_file.write("    virtual ~MessageFactoryImp();\n")
		head_file.write("    virtual void init_msg_map();\n")
		head_file.write("    static MessageFactoryImp *instance();\n")
		head_file.write("    static MessageFactoryImp *instance_;\n")
		head_file.write("};\n")
		head_file.write("#endif //_MESSAGEFACTORYIMP_H_\n")
	cpp_file_path = os.path.join(cpp_filepath, "MessageFactoryImp.cpp")
	with open(cpp_file_path, "w+", encoding='utf-8') as cpp_file :
		cpp_file.write("#include \"MessageFactoryImp.h\"\n")
		for proto_head_file in head_file_list:
			cpp_file.write("#include \"%s\"\n" % (proto_head_file))
		cpp_file.write("MessageFactoryImp::MessageFactoryImp(){}\n")
		cpp_file.write("MessageFactoryImp::~MessageFactoryImp(){}\n")
		cpp_file.write("MessageFactoryImp *MessageFactoryImp::instance_ = NULL;\n")
		cpp_file.write("MessageFactoryImp *MessageFactoryImp::instance() {\n")
		cpp_file.write("    if (MessageFactoryImp::instance_ == NULL) {\n")
		cpp_file.write("        MessageFactoryImp::instance_ = new MessageFactoryImp();\n")
		cpp_file.write("        MessageFactoryImp::instance_->init();\n")
		cpp_file.write("    }\n")
		cpp_file.write("    return MessageFactoryImp::instance_;\n")
		cpp_file.write("}\n")
		cpp_file.write("void MessageFactoryImp::init_msg_map() {\n")
		cpp_file.write("    // == auto gen code here\n")
		for message_name in message_name_list:
			cpp_file.write("    this->register_message(\"%s\", new %s());\n" % (message_name, message_name))
		cpp_file.write("}\n")

def generate_proto_define(head_file_list, cpp_filepath):
	head_file_path = os.path.join(cpp_filepath, "ProtoDefine.h")
	with open(head_file_path, "w+", encoding='utf-8') as head_file :
		head_file.write("#ifndef _PROTODEFINE_H_\n")
		head_file.write("#define _PROTODEFINE_H_\n")
		for name in head_file_list :
			head_file.write("#include \"%s\"\n" % (name))
		head_file.write("#endif //_PROTODEFINE_H_\n")
		head_file.write("\n")

#############################################################

def main():
	(opt, args) = parseOption(sys.argv)
	cpp_filepath=opt.cpp_out
	message_name_list = []
	head_file_list = []
	for root_proto_path, dirs, files in os.walk(opt.proto_path) :
		for filename_proto in files :
			(filename, ext) = os.path.splitext(filename_proto)
			if ext != ".proto" :
				continue
			proto_filepath = os.path.join(root_proto_path, filename_proto)
			(message_map, include_list, message_name_list) = read_proto_file(proto_filepath, message_name_list)
			head_file_list.append(filename + ".pb.h")
			#_print(include_list)
			#_print(message_map)
			generate_message_h(message_map, include_list, cpp_filepath, filename)
			generate_message_cpp(message_map, cpp_filepath, filename)
	generate_message_factory_imp(head_file_list, message_name_list, cpp_filepath)
	generate_proto_define(head_file_list, cpp_filepath)	

if __name__ == '__main__':
	try:
		main()
	except Exception as e:
		traceback.print_exc()
		_print(e)
		do_exit(90)